
#ifndef __KHAN_VTY_SESSION_HPP__ 
#define __KHAN_VTY_SESSION_HPP__ 

#include "khan.hpp"
#include "vty.hpp"
#include "io_session.hpp"
#include "vty_input.hpp"
#include "telnet_opt.hpp"
#include "pty_shell.hpp"

#include "command_manager.hpp"

class vty_manager;

class vty_session
: public vty,
public io_session,
public boost::enable_shared_from_this<vty_session>,                               
private boost::noncopyable       
{
public:
    enum { _def_max_buf_size_ = (8192*4) };
    typedef enum { 
        _all_,
        _socket_input_, _socket_output_,  
        _pty_input_, _pty_output_  
    } direction;

    explicit vty_session(__u32 id, io_service& io_service, 
            vty_manager& manager, command_manager& cmdmng);
    ~vty_session() { PDBG(" delete vty session \n"); };

    /* vty interface */
    void start();
    void stop();

    void receive_alram(const std::string& msg);

    void set_func_flag(bool flag) { _flag = flag; };
    bool get_func_flag() { return _flag; };

    int id() { return _id; };

    tcp_socket& socket() { return *_socket; }

    bool is_auth_mode() { 
        return _cmdmng.is_auth(_mode); 
    }
    bool is_auth_mode(const std::string& mode) { return _cmdmng.is_auth(mode); }

    const std::string prompt() { return _cmdmng.prompt(_mode); }
    const std::string get_banner() { return _cmdmng.get_banner(); }
    void set_banner(const std::string& banner) { _cmdmng.set_banner(banner); }

    bool check_passwd(const std::string passwd) { 
        return (_cmdmng.get_passwd().compare(passwd) == 0); };

    bool change_mode(const std::string& mode) {
        if (!_cmdmng.is_exist(mode)) return false;
        _mode = mode; return  true; 
    };

    const std::string current_mode() { 
        //PDBG("current mode: %s\n", _mode.c_str());
        return _mode; 
    };

    int output(const char c);
    int output(const char* fmt, ...);
    int output(const std::string& string);

    bool is_stop() { return _is_stopping; };
    bool is_dialog() { return (_diag != NULL); };
    int stop_dialog() { _diag = NULL;  return 0; };
    int start_dialog(DialogHandle func) { 
        if (_diag != NULL) return -1;
        _diag = func;
        _diag(shared_from_this(), "");
        return 0;
    };

    bool is_pty() { return (_ptystream.use_count() != 0); };
    void excute_pty(const string_vector& cmdvec);
    void excute_command(const std::string commandline);
    void describe_command(const std::string commandline);
    void complete_command(const std::string commandline);

    void flush(direction dir = _all_);

private:
	typedef std::deque<std::string> 	string_queue_t;
	typedef string_queue_t::iterator	string_queue_iterator;

    void write_sock();
    void write_pty(const std::string data);

    void close();
    void close_pty();

    void handle_ingress_sock(std::string& input);

    void handle_write_alarm( const boost::system::error_code& e,
                std::size_t bytes_transferred);
    void handle_read_pty( const boost::system::error_code& e,
                std::size_t bytes_transferred);
    void handle_write_pty( const boost::system::error_code& e,
                std::size_t bytes_transferred);
    void handle_read_sock( const boost::system::error_code& e,
                std::size_t bytes_transferred);
    void handle_write_sock( const boost::system::error_code& e,
                std::size_t bytes_transferred);

    __u32 _id;
    bool _flag;
    io_service&     _io_service;
    boost::asio::io_service::strand _strand;
    tcp_socket_ptr  _socket;
    vty_manager&     _manager;
    command_manager& _cmdmng;
    vty_input_ptr   _input; /* FIXME */
    pty_shell_ptr _pty_shell;
    stream_descriptor_ptr  _ptystream;
    telnet_opt  _telnet_opt;
    std::string _mode;
    DialogHandle  _diag;
    bool _is_stopping;

    boost::array<char, _def_max_buf_size_>  _sbuf;
    boost::array<char, _def_max_buf_size_>  _pbuf;
    boost::asio::streambuf _osbuf;
    boost::asio::streambuf _pty_osbuf;
    std::ostream    _ostream;
    std::ostream    _pty_ostream;
	string_queue_t	_alarm_q;
};

typedef boost::shared_ptr<vty_session> vty_session_ptr;

#endif  /* __KHAN_VTY_SESSION_HPP__ */

